package controller

import (
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"strconv"
	"wms/define"
	"wms/logger"
	"wms/logic"
)

// GetRoleListHandler 获取角色列表
// @Summary 获取角色列表接口
// @Description 鉴权后用户需要提供（page,size,keyword）拉取对应角色列表信息
// @Tags 角色相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamRoleListPage true "分页信息"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/role/get/list [get]
func GetRoleListHandler(c *gin.Context) {
	p := new(define.ParamRoleListPage)
	if err := c.ShouldBindQuery(p); err != nil {
		zap.L().Error("SetRoleList bind query param failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	roleListCnt, roleLists, err := logic.GetRoleList(p)
	if err != nil {
		zap.L().Error("logic.GetRoleList failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}
	// 输出一下获取的角色列表信息
	logger.LogGetRolesInfo(roleLists)

	define.ResponseSuccess(c, define.CodeSuccessGetRoles, gin.H{
		"roleList":    roleLists,
		"roleListCnt": roleListCnt,
	})
}

// CreateRoleHandler 创建新角色
// @Summary 创建角色接口
// @Description 鉴权后用户需要提交角色信息创建角色
// @Tags 角色相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamRoleAdd true "角色基本信息"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/role/create [post]
func CreateRoleHandler(c *gin.Context) {
	p := new(define.ParamRoleAdd)
	p.MapMenu = make(map[string]uint, 0)
	if err := c.ShouldBindJSON(p); err != nil {
		zap.L().Error("CreateRole bind json param failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	// 前端序列化map不行，序列化map数组[...[k, v]]传上来的
	// [[identity, crud], ...]
	mapArray := make([][2]interface{}, 0)
	if err := json.Unmarshal([]byte(p.MapMenuStr), &mapArray); err != nil {
		zap.L().Error("CreateRoleHandler json.Unmarshal failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	for _, v := range mapArray {
		identity := v[0].(string)
		crud, _ := strconv.ParseUint(strconv.FormatFloat(v[1].(float64), 'g', -1, 64), 10, 64)
		p.MapMenu[identity] = uint(crud)
	}

	if err := logic.CreateRole(p); err != nil {
		zap.L().Error("logic.CreateRole failed", zap.Error(err))
		if errors.Is(err, define.MysqlErrorRoleNameExist) {
			define.ResponseError(c, define.CodeRoleNameExist)
			return
		}
		define.ResponseError(c, define.CodeServerBusy)
		return
	}
	define.ResponseSuccess(c, define.CodeSuccessCreateRole, nil)
}

// DeleteRoleHandler 删除角色
// @Summary 创建角色接口
// @Description 鉴权后用户需要提交角色唯一标识删除角色
// @Tags 角色相关接口
// @Accept application/json
// @Produce application/json
// @Param Identity query string true "角色标识"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/role/delete [delete]
func DeleteRoleHandler(c *gin.Context) {
	identity := c.Query("identity")
	if identity == "" {
		zap.L().Error("DeleteRole param is empty")
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}

	if err := logic.DeleteRoleByIdentity(identity); err != nil {
		zap.L().Error("logic.DeleteRoleByIdentity failed", zap.Error(err))
		if errors.Is(err, define.MysqlErrorUserExistWithRole) {
			define.ResponseError(c, define.CodeRoleWithUser)
			return
		}
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessDelRole, nil)
	return
}

// GetRoleDetailHandler 获取角色详情，包含角色对应菜单信息
// @Summary 获取角色详情接口
// @Description 鉴权后用户需要提交角色唯一标识获取角色详情
// @Tags 角色相关接口
// @Accept application/json
// @Produce application/json
// @Param Identity query string true "角色标识"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/role/get/detail [get]
func GetRoleDetailHandler(c *gin.Context) {
	identity := c.Query("identity")
	if identity == "" {
		zap.L().Error("GetRole bind query param failed")
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}
	p := new(define.RoleDetailReply)
	if err := logic.GetRoleDetail(identity, p); err != nil {
		zap.L().Error("logic.GetRoleDetail failed", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}
	define.ResponseSuccess(c, define.CodeSuccessGetRoleDetail, p)
}

// UpdateRoleDetailHandler 更新角色详情
// @Summary 更新角色接口
// @Description 鉴权后用户需要提交角色信息更新角色详情
// @Tags 角色相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamRoleDetail true "角色详情信息"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/role/update [put]
func UpdateRoleDetailHandler(c *gin.Context) {
	p := new(define.ParamRoleDetail)
	p.MapMenu = make(map[string]uint, 0)
	if err := c.ShouldBindJSON(p); err != nil {
		errs, ok := err.(validator.ValidationErrors)
		if !ok {
			zap.L().Error("UpdateRoleDetail bind param failed", zap.Error(err))
			define.ResponseError(c, define.CodeInvalidParam)
			return
		}
		zap.L().Error("UpdateRoleDetail bind param failed, tag binding error", zap.Error(err))
		define.ResponseErrorWithMsg(c, define.CodeInvalidParam, define.RemoveTopStruct(errs.Translate(define.Trans)))
		return
	}

	// 同创建，也许要将 map_menu_str 转为 map_menu
	mapArray := make([][2]interface{}, 0)
	if err := json.Unmarshal([]byte(p.MapMenuStr), &mapArray); err != nil {
		zap.L().Error("CreateRoleHandler json.Unmarshal failed", zap.Error(err))
		define.ResponseError(c, define.CodeInvalidParam)
		return
	}
	for _, v := range mapArray {
		identity := v[0].(string)
		crud, _ := strconv.ParseUint(strconv.FormatFloat(v[1].(float64), 'g', -1, 64), 10, 64)
		p.MapMenu[identity] = uint(crud)
	}

	if err := logic.UpdateRoleDetail(p); err != nil {
		zap.L().Error("logic.UpdateRoleDetail failed", zap.Error(err))
		if errors.Is(err, define.MysqlErrorRoleNameExist) {
			define.ResponseError(c, define.CodeRoleNameExist)
			return
		}
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessUpdateRole, nil)
}

// UpdateRoleAdminHandler 更新角色管理员状态
// @Summary 更新角色管理员状态接口
// @Description 鉴权后用户需要提交角色标识及管理员标识更新角色管理员状态
// @Tags 角色相关接口
// @Accept application/json
// @Produce application/json
// @Param object body define.ParamRoleAdmin true "角色和管理标识"
// @Param Authorization header string true "Bearer 用户令牌"
// @Success 200 {object} define.DocResponseData
// @Router /settings/role/update/admin [put]
func UpdateRoleAdminHandler(c *gin.Context) {
	p := new(define.ParamRoleAdmin)
	if err := c.ShouldBindJSON(p); err != nil {
		errs, ok := err.(validator.ValidationErrors)
		if !ok {
			zap.L().Error("UpdateRoleAdmin bind param failed", zap.Error(err))
			define.ResponseError(c, define.CodeInvalidParam)
			return
		}
		zap.L().Error("UpdateRoleAdmin bind param failed, tag binding error")
		define.ResponseErrorWithMsg(c, define.CodeInvalidParam, define.RemoveTopStruct(errs.Translate(define.Trans)))
		return
	}

	if err := logic.UpdateRoleAdmin(p.Identity, p.IsAdmin); err != nil {
		zap.L().Error("logic.UpdateRoleAdmin", zap.Error(err))
		define.ResponseError(c, define.CodeServerBusy)
		return
	}

	define.ResponseSuccess(c, define.CodeSuccessUpdate, nil)
}
